package com.xuecheng.media.service.jobhandler;

import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.base.utils.VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.BigFilesService;
import com.xuecheng.media.service.MediaFileProcessService;
import com.xuecheng.media.service.MediaFileService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Author: chenheng
 * @Date: 2023/12/25 15:12
 */
@Component
@Slf4j
public class VideoTask {
    @Value("${videoprocess.ffmpegpath}")
    String ffmpegpath;
    @Autowired
    private MediaFileProcessService mediaFileProcessService;
    @Autowired
    BigFilesService bigFilesService;
    @Autowired
    MediaFileService mediaFileService;

    /**
     * 2、分片广播任务
     */
    @XxlJob("videoJobHandler")
    public void videoJobHandler() throws Exception {
        // 分片序号，从0开始
        int shardIndex = XxlJobHelper.getShardIndex();
        // 分片总数
        int shardTotal = XxlJobHelper.getShardTotal();
        List<MediaProcess> mediaProcesses = null;
        int size = 0;
        log.debug("----------开启任务------------------");
        //取出cpu核心数作为一次处理数据的条数
        int processors = Runtime.getRuntime().availableProcessors();
        //查询任务
        mediaProcesses = mediaFileProcessService.selectListByShardIndex(shardTotal, shardIndex, processors);
        size = mediaProcesses.size();
        log.debug("取出待处理视频任务{}条", size);
        if (size <= 0) {
            return;
        }
        //开启线程执行任务
        //计数器
        CountDownLatch countDownLatch = new CountDownLatch(size);
        //启动size个线程的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(size);
        //将处理任务加入线程池
        mediaProcesses.forEach(mediaProcess -> {
            threadPool.execute(() -> {
                try {
                    //taskId
                    Long taskId = mediaProcess.getId();
                    //争抢任务
                    boolean b = mediaFileProcessService.startTask(taskId);
                    if (!b) {
                        log.debug("争抢任务失败，taskId{}", taskId);
                    }
                    //执行任务
                    log.debug("开始执行任务，mediaProcess{}", mediaProcess);
                    //bucket
                    String bucket = mediaProcess.getBucket();
                    //objectName
                    String objectName = mediaProcess.getFilePath();
                    //fileId  == md3
                    String fileId = mediaProcess.getFileId();
                    //下载视频到本地
                    File originalFile = bigFilesService.downloadFileFromMinIO(bucket, objectName);
                    if (originalFile == null) {
                        log.debug("下载待处理视频失败，originalFile{}", originalFile);
                        //执行任务失败 跟新任务失败结果
                        mediaFileProcessService.saveProcessFinishStatus(taskId, "3", fileId, null, "下载待处理视频失败");
                        return;
                    }
                    //进行转码
                    //处理下载的视频文件
                    File mp4File = null;
                    try {
                        mp4File = File.createTempFile("mp4", ".mp4");
                    } catch (IOException e) {
                        log.debug("创建mp4临时文件失败");
                        mediaFileProcessService.saveProcessFinishStatus(taskId, "3", fileId, null, "创建mp4临时文件失败");
                        return;
                    }
                    String result = "";
                    try {
                        //视频处理结果
                        Mp4VideoUtil mp4VideoUtil = new Mp4VideoUtil(ffmpegpath, originalFile.getAbsolutePath(), mp4File.getName(), mp4File.getPath());
                        //开始视频转换，成功将返回success
                        result = mp4VideoUtil.generateMp4();
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("处理视频文件:{},出错:{}", mediaProcess.getFilePath(), e.getMessage());
                    }
                    if (!result.equals("success")) {
                        //记录错误信息
                        log.error("处理视频失败,视频地址:{},错误信息:{}", bucket + objectName, result);
                        mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", fileId, null, result);
                    }
                    //上传到minio
                    //mp4在minio的存储路径
                    String objectNames = getFilePath(fileId, ".mp4");
                    String url = "/" + bucket + "/" + objectNames;
                    try {
                        boolean b1 = mediaFileService.addMediaFilesToMinIO(mp4File.getAbsolutePath(), "video/mp4", mediaProcess.getBucket(), objectNames);
                        //将url存储至数据，并更新状态为成功，并将待处理视频记录删除存入历史
                        mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "2", fileId, url, null);
                    } catch (Exception e) {
                        log.error("上传视频失败或入库失败,视频地址:{},错误信息:{}", bucket + objectNames, e.getMessage());
                        //最终还是失败了
                        mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", fileId, null, "处理后视频上传或入库失败");
                    }
                } finally {
                    countDownLatch.countDown();
                }
            });
        });
        //等待,给一个充裕的超时时间,防止无限等待，到达超时时间还没有处理完成则结束任务
        countDownLatch.await(30, TimeUnit.MINUTES);
    }

    private String getFilePath(String fileMd5, String fileExt) {
        return fileMd5.substring(0, 1) + "/" + fileMd5.substring(1, 2) + "/" + fileMd5 + "/" + fileMd5 + fileExt;
    }
}
